热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

时调|都会_分布式定时任务调度框架Quartz学习与实战记录完整篇

篇首语:本文由编程笔记#小编为大家整理,主要介绍了分布式定时任务调度框架Quartz学习与实战记录完整篇相关的知识,希望对你有一定的参考价值。1.Quartz的

篇首语:本文由编程笔记#小编为大家整理,主要介绍了分布式定时任务调度框架Quartz学习与实战记录完整篇相关的知识,希望对你有一定的参考价值。



1.Quartz的概念

Quartz就是一个基于Java实现的任务调度框架,用于执行你想要执行的任何任务。
Quartz是OpenSymphony开源组织在Job scheduling(定时调度)领域的开源项目,它可以与J2EE和J2SE应用程序相结合也可以单独使用。

Quartz是开源且具有丰富特性的任务调度库,能够集成任何的Java应用。它能创建简单的或者复杂的调度任务,以执行上十,上百,上千,上万的任务。任务job被定义为标准的Java组件。能工执行任何你想要实现的功能。Quartz调度框架包含许多企业级的特性,如JTA事务,集群的支持。



官网:http://www.quartz-scheduler.org/



2.Quartz运行环境


  • Quartz可以运行嵌入在另一个独立的应用程序中
  • Quartz可以在应用程序服务器(或servlet容器)内被实例化,bin参与事务
  • Quartz可以作为一个独立的程序运行(其自己的java虚拟机内),可以通过RMI使用
  • Quartz可以被实例化,作为独立的项目集群(负载平衡和故障转移功能),用于作业执行

3.Quartz使用的设计模式


  • Builder模式
  • Factory模式
  • 组件模式
  • 链式编程

4.Quartz学习的核心概念


  • 任务Job


job就是你想实现的任务类,每一个job必须实现org.quartz.job接口,且只需实现接口定义的execute()方法



  • 触发器Trigger


Trigger为你执行任务的触发器(定时)
Trigger主要包含两个SimpleTrigger和CronTrigger两种



  • 调度器Scheduler


Scheduler为定时任务调度,它会将任务Job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job



5.Quartz的体系结构


6.Quartz的几个常用API


  • Scheduler:用于定时调度程序交互的主程序接口。Scheduler调度程序:任务执行计划表,只有安排进执行计划的任务Job【通过scheduler.scheduleJob方法安排进执行任务】,当它预先定义的执行时间到了的时候(任务出发trigger)该任务才会被执行

  • Job:预先定义的,希望在未来某个使劲能被调度程序执行的任务类,可自定义

  • JobDetail:使用JobDetail来定义定时任务的实例,JobDetail实例是通过JobBuilder类创建的

  • JobDataMap:可以包含不限量(序列化的)的数对象,在Job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本类型数据的方法

  • Trigger:触发器,Trigger对象是用来触发执行Job的。当调度一个Job时,我们实例一个触发器然后调整他的属性来满足Job执行的条件。表明任务在什么时候会执行。【定义了一个已经被安排的任务将会在什么时候执行的时间条件】

  • JobBuilder:用于声明一个任务实例,也可以定义关于该任务的详情比如任务名,组名等。通过JobBuilder声明的实例将会作为一个实际执行的任务。

  • TriggerBuilder:触发器创建器,用于创建触发器trigger实例

  • JobListener、TriggerListener、SchedulerListener监听器,用于对组件的监听


7.入门案例



构建一个任务类实现Job接口,重写execute(执行方法)方法,在执行方法中编写定时调度需要实现的逻辑。
创建一个main方法,在main方法中构建任务实例和处方实例有调度器实例进行绑定并开启任务。



7.1.pom.xml

<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
<version>2.3.0version>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartz-jobsartifactId>
<version>2.3.0version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>

7.2.任务类

/**
* &#64;Author ScholarTang
* &#64;Date 2021/7/13 10:45
* &#64;Desc 任务类
*/

&#64;Slf4j
public class HelloJob implements Job
&#64;Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) &#43; " | 任务被执行了");



7.3.调度器

/**
* &#64;Author ScholarTang
* &#64;Date 2021/7/13 10:53
* &#64;Desc 调度器
*/

public class HelloSchedulerDemo
public static void main(String[] args) throws SchedulerException
//从调度工厂中获取调度器实例
Scheduler scheduler &#61; StdSchedulerFactory.getDefaultScheduler();
//通过JobBuilder构建一个任务实例
JobDetail jobDetail &#61; JobBuilder.newJob(HelloJob.class)
//设置任务的唯一实例名称和任务组名称组名
.withIdentity("job1", "group1")
//构建实例
.build();
//通过TriggerBuilder构建触发器实例
SimpleTrigger trigger &#61; TriggerBuilder.newTrigger()
//设置触发器唯一实例名称和触发器的组名
.withIdentity("trigger1", "group1")
//执行计划&#xff0c;每五秒执行一次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
//立即执行
.startNow()
//构建实例
.build();
//调度器绑定任务实例和触发器
scheduler.scheduleJob(jobDetail,trigger);
//开启定时任务
scheduler.start();



7.4.执行结果


8.Job和JobDetail的关系介绍


  • Job&#xff1a;工作任务调度接口&#xff0c;任务类需要实现的接口。该接口中定义了execute方法&#xff0c;类似JDK提供的TimeTask类的run方法。在这里面编写任务执行的业务逻辑
  • Job实例在Quartz中的生命周期&#xff1a;每次调度器执行Job时&#xff0c;它在调用execute方法前会创建一个新的Job实例&#xff0c;当调度完成后&#xff0c;管理的Job对象实例将会被释放&#xff0c;释放的实例会被垃圾回收机制回收

&#64;Slf4j
public class HelloJob implements Job
public HelloJob()
log.info("实例被创建了");

&#64;Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) &#43; " | 任务被执行了");



  • JobDetail&#xff1a;JobDetail为Job实例提供了许多设置属性&#xff0c;已经JobDetaMap成员变量属性&#xff0c;它用来存储特定Job实例的状态信息&#xff0c;调度器需要借助于JobDetail对象来添加Job实例【JobDetail中重要的属性&#xff1a;name[任务实例的唯一标识名称]、group[任务调度实例的组名]、jobClass[任务类信息]、jobDataMap】

&#64;Slf4j
public class HelloSchedulerDemo
public static void main(String[] args) throws SchedulerException
//从调度工厂中获取调度器实例
Scheduler scheduler &#61; StdSchedulerFactory.getDefaultScheduler();
//通过JobBuilder构建一个任务实例
JobDetail jobDetail &#61; JobBuilder.newJob(HelloJob.class)
//设置任务的唯一实例名称和任务组名称组名
.withIdentity("job1", "group1")
//构建实例
.build();
//jobDataMap
JobDataMap jobDataMap &#61; jobDetail.getJobDataMap();
//任务实例的唯一标识名称
String name &#61; jobDetail.getKey().getName();
//任务调度实例的组名
String group &#61; jobDetail.getKey().getGroup();
//任务类信息
String clazzName &#61; jobDetail.getKey().getClass().getName();
log.info("jobDataMap:", jobDataMap);
log.info("任务实例的唯一标识名称&#xff1a;"&#43;name);
log.info("任务调度实例的组名&#xff1a;"&#43;group);
log.info("任务类信息&#xff1a;"&#43;clazzName);
//通过TriggerBuilder构建触发器实例
SimpleTrigger trigger &#61; TriggerBuilder.newTrigger()
//设置触发器唯一实例名称和触发器的组名
.withIdentity("trigger1", "group1")
//执行计划&#xff0c;每五秒执行一次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
//立即执行
.startNow()
//构建实例
.build();
//调度器绑定任务实例和触发器
scheduler.scheduleJob(jobDetail,trigger);
//开启定时任务
scheduler.start();



9.JobExecutionContext的介绍


  • 当Scheduler调用一个Job&#xff0c;就会将JobExecutionContext传递给Job的execute()方法

  • Job能通过JobExecuteContext对象访问到Quartz运行时的环境以及Job本身的明细数据


    • 获取JobDetail相关信息、获取Trigger相关信息、获取Job类本身的信息

    /**
    * &#64;Author ScholarTang
    * &#64;Date 2021/7/13 10:45
    * &#64;Desc 任务类
    */

    &#64;Slf4j
    public class HelloJob implements Job
    &#64;Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
    //通过JobExecutionContext获取JobDetail
    JobDetail jobDetail &#61; jobExecutionContext.getJobDetail();
    JobKey jobKey &#61; jobDetail.getKey();
    String jobDetailName &#61; jobKey.getName();
    String jobDetailGroup &#61; jobKey.getGroup();
    String jobClazzNameJobDetail &#61; jobKey.getClass().getName();
    log.info("任务实例的唯一标识名称&#xff1a;" &#43; jobDetailName);
    log.info("任务实例的组名&#xff1a;" &#43; jobDetailGroup);
    log.info("任务实例绑定的任务类信息&#xff1a;" &#43; jobClazzNameJobDetail);
    log.info("-----------------------------------------");
    //通过JobExecutionContext获取Trigger
    Trigger trigger &#61; jobExecutionContext.getTrigger();
    TriggerKey triggerKey &#61; trigger.getKey();
    String triggerKeyName &#61; triggerKey.getName();
    String triggerKeyGroup &#61; triggerKey.getGroup();
    String triggerClazzName &#61; triggerKey.getClass().getName();
    log.info("触发器的唯一标识名称&#xff1a;" &#43; triggerKeyName);
    log.info("触发器的组名&#xff1a;" &#43; triggerKeyGroup);
    log.info("触发器绑定的任务类信息&#xff1a;" &#43; triggerClazzName);
    log.info("-----------------------------------------");
    //通过JobExecutionContext
    String jobClazzName &#61; jobExecutionContext.getClass().getName();
    log.info("job类相关的信息&#xff1a;"&#43;jobClazzName);
    log.info("-----------------------------------------");
    log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) &#43; " | 任务被执行了");



10.JobDataMap介绍


10.1.使用Map获取


  • 在进行任务调度时&#xff0c;JobDataMap存储在JobExecutionContent中&#xff0c;非常方便获取
  • JobDataMap可以用来存储任何可序列化的数据对象&#xff0c;当Job实例对象被执行时这些参数都会传递给它
  • JobDataMap实现了JDK的Map接口&#xff0c;并且添加了非常方便的方法来存储基本数据类型

/**
* &#64;Author ScholarTang
* &#64;Date 2021/7/13 10:53
* &#64;Desc 调度器
*/

&#64;Slf4j
public class HelloSchedulerDemo
public static void main(String[] args) throws SchedulerException
//从调度工厂中获取调度器实例
Scheduler scheduler &#61; StdSchedulerFactory.getDefaultScheduler();
//通过JobBuilder构建一个任务实例
JobDetail jobDetail &#61; JobBuilder.newJob(HelloJob.class)
//设置任务的唯一实例名称和任务组名称组名
.withIdentity("job1", "group1")
//设置jobDataMap数据 <<&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
.usingJobData("message","勇敢牛牛、不怕困难")
//构建实例
.build();
//通过TriggerBuilder构建触发器实例
SimpleTrigger trigger &#61; TriggerBuilder.newTrigger()
//设置触发器唯一实例名称和触发器的组名
.withIdentity("trigger1", "group1")
//设置jobDataMap数据 <<&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
.usingJobData("username","张三")
//执行计划&#xff0c;每五秒执行一次
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5))
//立即执行
.startNow()
//构建实例
.build();
//调度器绑定任务实例和触发器
scheduler.scheduleJob(jobDetail,trigger);
//开启定时任务
scheduler.start();


/**
* &#64;Author ScholarTang
* &#64;Date 2021/7/13 10:45
* &#64;Desc 任务类
*/

&#64;Slf4j
public class HelloJob implements Job
&#64;Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
//通过JobExecutionContext获取JobDetail
JobDetail jobDetail &#61; jobExecutionContext.getJobDetail();
JobKey jobKey &#61; jobDetail.getKey();
String jobDetailName &#61; jobKey.getName();
String jobDetailGroup &#61; jobKey.getGroup();
String jobClazzNameJobDetail &#61; jobKey.getClass().getName();
log.info("任务实例的唯一标识名称&#xff1a;" &#43; jobDetailName);
log.info("任务实例的组名&#xff1a;" &#43; jobDetailGroup);
log.info("任务实例绑定的任务类信息&#xff1a;" &#43; jobClazzNameJobDetail);
log.info("-----------------------------------------");
//通过JobExecutionContext获取Trigger
Trigger trigger &#61; jobExecutionContext.getTrigger();
TriggerKey triggerKey &#61; trigger.getKey();
String triggerKeyName &#61; triggerKey.getName();
String triggerKeyGroup &#61; triggerKey.getGroup();
String triggerClazzName &#61; triggerKey.getClass().getName();
log.info("触发器的唯一标识名称&#xff1a;" &#43; triggerKeyName);
log.info("触发器的组名&#xff1a;" &#43; triggerKeyGroup);
log.info("触发器绑定的任务类信息&#xff1a;" &#43; triggerClazzName);
log.info("-----------------------------------------");
//通过JobExecutionContext
String jobClazzName &#61; jobExecutionContext.getClass().getName();
log.info("job类相关的信息&#xff1a;"&#43;jobClazzName);
log.info("-----------------------------------------");
//获取JobDetail中JobDataMap中的message内容 <<&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
JobDataMap jobDataMap &#61; jobDetail.getJobDataMap();
String message &#61; jobDataMap.getString("message");
log.info("从JobDetail-JobDataMap中或到的message内容为&#xff1a;" &#43; message);
//获取Trigger中JobDataMap中的username内容 <<&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
JobDataMap triggerJobDataMap &#61; trigger.getJobDataMap();
String username &#61; triggerJobDataMap.getString("username");
log.info("从Trigger-JobDataMap中获取到的username内容为&#xff1a;" &#43; username);
log.info("-----------------------------------------");
log.info(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()) &#43; " | 任务被执行了");



10.2.Job实现类中添加setter方法对应JobDataMap的键值&#xff0c;Quartz框架默认的JobFactory实现类在初始化Job实例对象时会自动的调用这些setter方法



调度器的内容是不变的。
注意&#xff1a;如果任务实例和触发器的JobDataMap中使用的是同一个key那么触发器的JobDataMap值会覆盖掉任务实例的值


/**
* &#64;Author ScholarTang
* &#64;Date 2021/7/13 10:45
* &#64;Desc 任务类
*/

&#64;Slf4j
public class HelloJob implements Job
private String message;
private String username;
public void setMessage(String message)
this.message &#61; message;

public void setUsername(String username)
this.username &#61; username;

&#64;Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
//通过JobExecutionContext获取JobDetail
JobDetail jobDetail &#61; jobExecutionContext.getJobDetail();
JobKey jobKey &#61; jobDetail.getKey();
String jobDetailName &#61; jobKey.getName();
String jobDetailGroup &#61; jobKey.getGroup();
String jobClazzNameJobDetail &#61; jobKey.getClass().getName();
log.info("任务实例的唯一标识名称&#xff1a;" &#43; jobDetailName);
log.info("任务实例的组名&#xff1a;" &#43; jobDetailGroup);
log.info("任务实例绑定的任务类信息&#xff1a;" &#43; jobClazzNameJobDetail);
log.info("-----------------------------------------");
//通过JobExecutionContext获取Trigger
Trigger trigger &#61; jobExecutionContext.getTrigger();
TriggerKey triggerKey &#61; trigger.getKey();
String triggerKeyName &#61; triggerKey.getName();
String triggerKeyGroup &#61; triggerKey.getGroup();
String triggerClazzName &#61; triggerKey.getClass().getName();
log.info("触发器的唯一标识名称&#xff1a;" &#43; triggerKeyName);
log.info("触发器的组名&#xff1a;" &#43; triggerKeyGroup);
log.info("触发器绑定的任务类信息&#xff1a;" &#43; triggerClazzName);
log.info("-----------------------------------------");
//通过JobExecutionContext
String jobClazzName &#61; jobExecutionContext.getClass().getName();
log.info("job类相关的信息&#xff1a;"&#43;jobClazzName)

推荐阅读
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 本文详细介绍了解决全栈跨域问题的方法及步骤,包括添加权限、设置Access-Control-Allow-Origin、白名单等。通过这些操作,可以实现在不同服务器上的数据访问,并解决后台报错问题。同时,还提供了解决second页面访问数据的方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
author-avatar
用户v6poho0s7u
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有